
import sys
from  datetime import datetime
import dateutil.parser
from html import escape
from bs4 import BeautifulSoup

def get_config(filename):
    import os
    import toml
    if not os.path.exists(filename):
        return None
    try:
        with open(filename,'r') as f:
            return toml.loads(f.read())
    except toml.decoder.TomlDecodeError as e:
        print("error in ", filename, ": ", e, file=sys.stderr)

def read_mail(path): # main loop
    from os import listdir, system
    from email import message_from_file, policy
    # don't need base64.b64decode -  already done by get_content()'
    def test(eml_obj):
        i = 0
        for part in eml_obj.walk():
            print(i, file=sys.stderr)
            if "From" in part:
                print(part["From"], file=sys.stderr)
            elif "Content-transfer-encoding" in part:
                print(part.get_content(), file=sys.stderr)
            i += 1
        # for part in eml_obj.walk():
        #     ct = part["Content-Type"]
        #     print(ct.find("text/html"), file=sys.stderr)
        #     if ct.find("text/html") != -1:
        #         print("This is formatted in html", file=sys.stderr)
        return
    try:
        # ignore hidden files (linux)
        files = [f for f in listdir(path) \
            if not f.startswith('.')]
    except FileNotFoundError as e:
        print(e, file=sys.stderr)
        return []
    messages = []
    for email in files:
        with open("%s/%s" % (path, email), 'r') as f:
            e = message_from_file(f,  policy=policy.default)
            if e.is_multipart():
                # test(e)
                messages.append(e)
            else:
                # print(e.get_content(), file=sys.stderr)
                messages.append(e)
    return messages

class n00:
    def __init__ (self, eml_obj):
        self.email_object = eml_obj
        if not eml_obj.is_multipart():
            self.sender = eml_obj["From"]
            self.date   = eml_obj["Date"]
            # self.msg    = eml_obj.get_content()
            return
        for part in eml_obj.walk():
            if "From" in part:
                self.sender = part["From"]
            if "Date" in part:
                self.date = part["Date"]
            # elif "Content-transfer-encoding" in part:
                # self.msg = part.get_content()

    def get_formatted_time(self, strf):
        t = dateutil.parser.parse(self.date)
        return t.strftime(strf)

    def get_epoch_time(self):
        if isinstance(self.date, int):
            return self.date
        t = dateutil.parser.parse(self.date)
        return int(t.timestamp())

    def get_message(self, whitelist=[]):
        def markup(text):
            return text.replace("\n", "<br>")
        def checks(e, is_trusted):
            if "Content-Type" not in e:
                return
            if e["Content-Type"].find("text/plain") != -1:
                return markup(e.get_content())
            if e["Content-Type"].find("text/html") != -1:
                if is_trusted:
                    return e.get_content()
                else:
                    return escape(e.get_content())                
        if not self.email_object.is_multipart():
            return checks(
                self.email_object, self.sender in whitelist)
        else:
            for part in self.email_object.walk():
                if "From" in part:
                    continue
                elif  "Content-transfer-encoding" in part:
                    return checks(
                        part, self.sender in whitelist)  
                pass

    def nm00(self, alias=""):
        end = len(self.sender)
        if self.sender[-1] == ">":
            end -= 1
        domain = self.sender[self.sender.find('@'):end]
        return alias + domain

    def nm01(self):
        return self.sender[:self.sender.find('@')]

def diff_demo(text, file2, debug=False):
    def diff_by_word(message, base, debug=False):
        i = 0
        output = []
        v = dict()
        for word in message:
            try:
                if debug:
                    print(base[i], " cmp ", word)
                if base[i] == "{__username__}":
                    i += 1
                    v["username"] = word
                elif "{__message__}" in base[i]:
                    i += 1
                elif "{__link__}" in base[i]:
                    i += 1
                    v["link"] = word
                if base[i] == word:
                    i += 1
                else:
                    output.append(word)
                    if "{keep}" in base[i]:
                        i += 1
            except IndexError:
                output.append(word)
        return v, " ".join(output)
    base = []
    message = []
    output = dict()
    output["message"] = []
    # with open(file1) as f:
    soup = BeautifulSoup(text, "html.parser")
        # get text, add whitespace where tag was removed
        # soup has no effect if the string is plain test
    message = soup.get_text(separator='\n').split('\n')
    with open(file2, 'r') as f:
        soup = BeautifulSoup(f.read(), "html.parser")
        base = soup.get_text(separator='\n').split('\n')
    i = 0
    for line in message:
        b = base[i].split()
        if "{__username__}" not in b \
        and "{__message__}" not in b \
        and "{__link__}" not in b \
        and "{keep}" not in b:
            i += 1
            continue
        d, l = (diff_by_word(line.split(), b))
        output.update(d)
        output["message"].append(l)
        i += 1
    if debug:
        print(output, file=sys.stderr)
    return output

def render(html_conf, diff_conf, eml_objs):
    def edit_after_match(diffed, params): 
        # diffed parameter is a dict()
        output = str()
        highlight = params["highlight"]
        if params["keep_link_in_message"] == False:
            diffed["message"].remove(diffed["link"])
        new_msg = "\n".join(
            [("<p>%s</p>" % line) for line in diffed["message"]])
        if highlight != str():
           tagged = highlight.format(username=diffed["username"])
           output = new_msg.replace(diffed["username"], tagged)
        return output

    if len(eml_objs) == 0:
        return
    html = [] # list of strings
    nz   = []
    model = html_conf["model"]
    for e in eml_objs:
        nz.append(n00(e))
    nz.sort(key=lambda a: a.get_epoch_time(), reverse=True)
    for n in nz: 
        if n.sender not in html_conf["anonymity"]["excluded"]:
            sender = n.nm00(alias=html_conf["anonymity"]["alias"])
        else:
            sender = n.sender
        date   = n.get_formatted_time(html_conf["date-format"])
        msg    = n.get_message( html_conf["whitelist"] )
        # print(msg, file=sys.stderr)
        matches  = [t for t in diff_conf["services"] if n.sender == t.get("sender")]
        if matches != []:
            match = matches.pop()
            d = diff_demo(msg, match["filter"], debug=False)
            msg = edit_after_match(d, match)
            new_date = "<a href=\"%s\">%s</a>" % (d["link"], date)
            date = new_date
        d = model.format(
            sender=sender, date=date, message=msg)
        html.append(d)
    with open(html_conf["page"], 'r') as f:
        page_template = f.read()
        print(page_template.format(content="\n".join(html)))
    return

if __name__ == "__main__":
    def get_args():
        import argparse
        ap = argparse.ArgumentParser()
        ap.add_argument("-c", "--config")
        args = ap.parse_args()
        return args.config
    
    def main(config_file):
        conf = get_config(config_file)
        if conf != None:
            email = read_mail(conf["inbox"])
            # for each in email:
                # print(n00(each).get_message(conf["html"]["whitelist"]), file=sys.stderr)
            render(conf["html"], conf["diff"], email)
        print("Finished.", file=sys.stderr)
    try:
        main(get_args())
        # diff_demo("testb-1.txt", "testb-2.txt", debug=True)
    except FileNotFoundError as e:
        print(e, file=sys.stderr)
